#pragma once
#include <unistd.h>
#include <iostream>
#include <filesystem>
#include <fstream>
#include <ctime>
#include <cassert>
#include <memory>
#include <sstream>
#include "Mutex.hpp"

using namespace MutexMudole;

namespace LogMoudle
{

    inline std::string format_local_time()
    {
        std::time_t t = std::time(nullptr);
        std::tm tm_buf{};
#if defined(_WIN32)
        localtime_s(&tm_buf, &t);
#else
        localtime_r(&t, &tm_buf);
#endif
        char buf[64];
        if (std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm_buf) == 0)
            return "[time-error]";
        return std::string(buf);
    }

    const std::string thisPath = "./log.txt";

    enum LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };

    inline std::string GetLevelStr(LogLevel level)
    {
        switch (level)
        {
        case DEBUG:
            return "DEBUG";
        case INFO:
            return "INFO";
        case WARNING:
            return "WARNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
        }
    }

    class Logstrate
    {
    protected:
        Logstrate() = default;

    public:
        virtual void LogPrint(std::string &infor) = 0;
    };

    /* ---------- 文件日志 ---------- */
    class FileLogstrate : public Logstrate
    {
    public:
        FileLogstrate() = default; // 关键：public
        void LogPrint(std::string &infor) override
        {
            LockGuard lock(mutex_);
            std::ofstream ofs(thisPath, std::ios::app);
            if (!ofs)
            {
                std::cerr << "Failed to open log file: " << thisPath << std::endl;
                std::exit(-1);
            }
            ofs << infor << std::endl;
        }

    private:
        Mutex mutex_;
    };

    /* ---------- 屏幕日志 ---------- */
    class ScreenLogstrate : public Logstrate
    {
    public:
        ScreenLogstrate() = default; // 关键：public
        void LogPrint(std::string &infor) override
        {
            LockGuard lock(mutex_);
            std::cout << infor << std::endl;
        }

    private:
        Mutex mutex_;
    };

    /* ---------- Logger ---------- */
    class Logger
    {
    public:
        Logger() { LogConsole(); }
        ~Logger() = default;

        void EnableFileLog()
        {
            _fflush_strategy = std::make_unique<FileLogstrate>();
        }
        void LogConsole()
        {
            _fflush_strategy = std::make_unique<ScreenLogstrate>();
        }

        class LogeMessage
        {
        public:
            LogeMessage(LogLevel level,
                        const std::string &src_name,
                        int line_number,
                        Logger &logger)
                : level_(level),
                  str_name_(src_name),
                  line_(line_number),
                  _pid(getpid()),
                  _current_time(format_local_time()),
                  logger_(logger)
            {
                std::stringstream ss;
                ss << "[" << _current_time << "]"
                   << "[" << GetLevelStr(level) << "]"
                   << "[" << _pid << "]"
                   << "[" << str_name_ << "]"
                   << "[" << line_ << "]"
                   << " - ";
                _loginfo = ss.str();
            }

            template <typename T>
            LogeMessage &operator<<(const T &info)
            {
                std::stringstream ss;
                ss << info;
                _loginfo += ss.str();
                return *this;
            }

            ~LogeMessage()
            {
                if (logger_._fflush_strategy)
                    logger_._fflush_strategy->LogPrint(_loginfo);
            }

        private:
            size_t line_;
            LogLevel level_;
            std::string str_name_;
            std::string _current_time;
            std::string _loginfo;
            pid_t _pid;
            Logger &logger_;
        };

        LogeMessage operator()(LogLevel level,
                               const std::string &src_name,
                               int line_number)
        {
            return LogeMessage(level, src_name, line_number, *this);
        }

    private:
        std::unique_ptr<Logstrate> _fflush_strategy;
    };

    Logger log;
#define LOG(level) log(level, __FILE__, __LINE__)
#define Enable_Console_Log log.LogConsole() // 开启屏幕日志
#define Enable_File_Log log.EnableFileLog() // 开启文件日志
}